///////////////////////////////////////////////////////////////////////////////
// \author (c) DaLinCaiNiao
//             2022, Shanghai, China
//
// \license The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// \brief STM32 UART related functions.
//
// \version
// v0.0.1: 2022.03.20, Initial version.
///////////////////////////////////////////////////////////////////////////////

#include "uart.h"
#include "string.h"
#include <stdarg.h>

/* UART handler declaration */
UART_HandleTypeDef Uart1Handle;
UART_HandleTypeDef Uart2Handle;

uint8_t Uart1TxBuf[UART1_TX_BUF_SIZE];
uint8_t Uart1RxBuf[UART1_RX_BUF_SIZE];
UartBuf_t Uart1Buf =
{
#if UART_RECORD_LOST_NUM
	0,                      // TxLostNum
#endif
	Uart1TxBuf,        		// TxBuf
	0,                      // TxIn
	0,                      // TxOut
	UART1_TX_BUF_SIZE,      // TxSize

#if UART_RECORD_LOST_NUM
	0,                      // RxLostNum
#endif
	Uart1RxBuf,        		// RxBuf
	0,                      // RxIn
	0,                      // RxOut
	UART1_RX_BUF_SIZE,      // RxSize
};

uint8_t Uart2TxBuf[UART2_TX_BUF_SIZE];
uint8_t Uart2RxBuf[UART2_RX_BUF_SIZE];
UartBuf_t Uart2Buf =
{
#if UART_RECORD_LOST_NUM
	0,                      // TxLostNum
#endif
	Uart2TxBuf,        		// TxBuf
	0,                      // TxIn
	0,                      // TxOut
	UART2_TX_BUF_SIZE,      // TxSize

#if UART_RECORD_LOST_NUM
	0,                      // RxLostNum
#endif
	Uart2RxBuf,        		// RxBuf
	0,                      // RxIn
	0,                      // RxOut
	UART2_RX_BUF_SIZE,      // RxSize
};

#if USE_MY_PRINTF
#include "printf.c"
extern void PutCharToTxBuf(char data);
void _putchar(char character)
{
#if 0
	HAL_UART_Transmit(&UART_HANDLE, (uint8_t *)&character, 1, 100);
#elif 1
	PutCharToTxBuf(character);
#else
#if UART_BUF_SIZE_IS_2POW
	UART_BUF.TxBuf[UART_BUF.TxIn & (UART_BUF.TxSize - 1)] = (uint8_t)character;
	UART_BUF.TxIn++;
#else
	UART_BUF.TxBuf[UART_BUF.TxIn++] = character;
	UART_BUF.TxIn %= UART_BUF.TxSize;
#endif
    // Enable TX interrupt
    SET_BIT(UART_HANDLE.Instance->CR1, USART_CR1_TXEIE);
#endif
}
#else
#include "syscalls.c"
#ifdef __GNUC__
/* With GCC, small printf (option LD Linker->Libraries->Small printf
   set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */

/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
	/* Place your implementation of fputc here */
	/* e.g. write a character to the UART and Loop until the end of transmission */
#if 0
	HAL_UART_Transmit(&UART_HANDLE, (uint8_t *)&ch, 1, 100);
#else
#if UART_BUF_SIZE_IS_2POW
	UART_BUF.TxBuf[UART_BUF.TxIn & (UART_BUF.TxSize - 1)] = (uint8_t)ch;
	UART_BUF.TxIn++;
#else
	UART_BUF.TxBuf[UART_BUF.TxIn++] = (uint8_t)ch;
	UART_BUF.TxIn %= UART_BUF.TxSize;
#endif

	// Enable TX interrupt
	SET_BIT(UART_HANDLE.Instance->CR1, USART_CR1_TXEIE);
#endif

	return ch;
}
#endif

HAL_StatusTypeDef InitUart1(void)
{
	HAL_StatusTypeDef Status = HAL_OK;
	GPIO_InitTypeDef  GPIO_InitStruct;

	GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull      = GPIO_PULLUP;
	GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_HIGH;

	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_USART1_CLK_ENABLE();
	/* USART1 TX GPIO PA9  */
	GPIO_InitStruct.Pin       = GPIO_PIN_9;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	/* USART1 RX GPIO PA10  */
	GPIO_InitStruct.Pin 	  = GPIO_PIN_10;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
	HAL_NVIC_EnableIRQ(USART1_IRQn);

	Uart1Handle.Instance        = USART1;
	Uart1Handle.Init.BaudRate   = 115200;
	Uart1Handle.Init.WordLength = UART_WORDLENGTH_8B;
	Uart1Handle.Init.StopBits   = UART_STOPBITS_1;
	Uart1Handle.Init.Parity     = UART_PARITY_NONE;
	Uart1Handle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
	Uart1Handle.Init.Mode       = UART_MODE_TX_RX;
	Uart1Handle.Init.OverSampling = UART_OVERSAMPLING_16;
	Status = HAL_UART_Init(&Uart1Handle);
	if(HAL_OK == Status)
	{
	    SET_BIT(Uart1Handle.Instance->CR1, USART_CR1_RXNEIE);
	}

	return Status;
}

/* print debug info via host uart */
void CustomUartPrintf(char* fmt, ...)
{
    char buffer[UART1_TX_BUF_SIZE];
    uint16_t str_len = 0;
    va_list arg_ptr;

    if(NULL != fmt)
    {
        va_start(arg_ptr, fmt);
        vsnprintf(buffer, UART1_TX_BUF_SIZE, fmt, arg_ptr);
        va_end(arg_ptr);

        str_len = strlen(buffer);
        if(UART1_TX_BUF_SIZE < str_len)
        {
            str_len = UART1_TX_BUF_SIZE;
        }
//		SendToHost();
    }
}

// ���»��λ����������˼·�ο��������ӣ�
// https://www.cnblogs.com/zengzy/p/5139582.html
void UartIrqService(USART_TypeDef* UartX, UartBuf_t* Buf)
{
	uint32_t SR = UartX->SR;
	uint32_t CR1 = UartX->CR1;
	uint32_t CR3 = UartX->CR3;

	UNUSED(CR3);

    while(SR & USART_SR_RXNE)
    {
#if UART_RECORD_LOST_NUM
    	if(SR & USART_SR_ORE)
		{
    		Buf->RxLostNum++;
		}
#endif

#if UART_BUF_SIZE_IS_2POW
        if ((Buf->RxIn - Buf->RxOut) != Buf->RxSize)
        {
            Buf->RxBuf[Buf->RxIn & (Buf->RxSize - 1)] = (uint8_t)(UartX->DR & (uint8_t)0x00FF);
            Buf->RxIn++;
        }
#else
        if (((Buf->RxIn + 1) % Buf->RxSize) != Buf->RxOut)
        {
            Buf->RxBuf[Buf->RxIn++] = (uint8_t)(UartX->DR & (uint8_t)0x00FF);
            Buf->RxIn %= Buf->RxSize;
        }
#endif
        else
        {
            Buf->RxBuf[Buf->RxIn] = (uint8_t)(UartX->DR & (uint8_t)0x00FF);
#if UART_RECORD_LOST_NUM
            Buf->RxLostNum++;
#endif
        }

        SR = UartX->SR;
    }

    if((SR & USART_SR_TXE) && (CR1 & USART_CR1_TXEIE))
    {
        if(Buf->TxIn != Buf->TxOut)
        {
#if UART_BUF_SIZE_IS_2POW
        	UartX->DR = (uint8_t)(Buf->TxBuf[Buf->TxOut & (Buf->TxSize - 1)] & (uint8_t)0x00FF);
            Buf->TxOut++;
#else
        	UartX->DR = (uint8_t)(Buf->TxBuf[Buf->TxOut++] & (uint8_t)0x00FF);
            Buf->TxOut %= Buf->TxSize;
#endif
        }
        else
        {
    		CLEAR_BIT(UartX->CR1, USART_CR1_TXEIE);
        }
    }
}
